import random

from .models import User
from rest_framework import serializers
from rest_framework_jwt.settings import api_settings
from rest_framework_jwt.views import obtain_jwt_token  # 导入token签发认证的入口
from django.db.models import Q
from rest_framework.exceptions import APIException,ValidationError
from django.conf import settings
from django.core.cache import cache
from faker import Faker

jwt_payload_handler = api_settings.JWT_PAYLOAD_HANDLER
jwt_encode_handler = api_settings.JWT_ENCODE_HANDLER

##############################登录序列化################################
class CommonLoginSerializer():
    def _get_user(self,attrs):
        raise APIException('这个方法必须要重写')

    def _get_token(self,user):
        payload = jwt_payload_handler(user)
        token = jwt_encode_handler(payload)
        return token

    def validate(self, attrs):
        # 验证用户名密码逻辑----->签发token逻辑
        # username字段可能是用户，手机号，邮箱---->正则匹配----》 换一种方式 使用Q查询
        user = self._get_user(attrs)
        # 签发token
        token = self._get_token(user)
        # 把用户，token放在序列化类context中[上下文]
        # print(user.username)
        # print(111)
        self.context['username'] = user.username
        self.context['icon'] = settings.BACKEND_URL + user.icon.url
        self.context['token'] = token
        return attrs








class LoginUserSerializer(CommonLoginSerializer,serializers.ModelSerializer):
    # 字段自己的规则，username会走唯一性叫校验--->就过不了--->必须要重写该字段
    username = serializers.CharField(required=True)  # 前端没有传参数会报错

    class Meta:
        model = User
        fields = ['username', 'password']  # 只做数据校验---->写校验的字段


    def _get_user(self,attrs):
        username = attrs.get('username')
        password = attrs.get('password')
        user = User.objects.filter(Q(username=username)|Q(mobile=username)|Q(email=username)).first()
        # 登录接口，如果是用默认密码，不允许登录
        if user and user.check_password(password):
            # 说明用户名存在，密码再校验
            print(user)
            return user
        else:
            raise APIException('用户名或者密码错误')




class LoginUserSMSSerializer(CommonLoginSerializer,serializers.Serializer):
    code = serializers.CharField(max_length=4)
    mobile = serializers.CharField()


    def _get_user(self,attrs):
        # attrs 中有手机号码和验证码
        mobile = attrs.get('mobile')
        code = attrs.get('code')

        # 验证验证码是否正确
        old_code = cache.get('send_sms_code_%s' % mobile)
        # 如果是 debug模式，有个万能验证码，这样就不用真正发送短信了
        if code == old_code or (settings.DEBUG or code == '8888'):
            # 验证码正确，查出user
            user = User.objects.filter(mobile=mobile).first()
            if user:
                return user
            else:
                raise APIException('手机号没有注册')
        else:
            raise APIException('验证码错误')


###############################注册序列化############################################
# 注册：1 校验数据  2 保存  3 序列化用不要？存疑（这里有两种情况）
class UserRegisterSerializer(serializers.ModelSerializer):
    code = serializers.CharField(max_length=4, min_length=4,write_only=True)

    class Meta:
        model = User
        fields = ['mobile', 'password', 'code']  # code 不是数据库的字段，需要重写

    # 如果想要限制密码强度，这里可以写个局部钩子

    def _check_code(self,attrs):
        mobile = attrs.get('mobile')
        code = attrs.get('code')
        old_code = cache.get('send_sms_code_%s' % mobile)
        if not (code == old_code or (settings.DEBUG and code == '8888')):
            raise APIException('验证码错误')


    def _pre_save(self,attrs):  # {mobile:122222,code:8888,password:123}
        attrs.pop('code')

        fake = Faker(locale='zh_CN')

        random_name = fake.name()
        attrs['username'] = random_name  # 默认用户名就是手机号  可以随机生成用户名  随机生成有意义的名字（ Faker）

    def validate(self,attrs):
        # 写逻辑
        # 1.检验验证码是否正确
        self._check_code(attrs)
        # 2. 入口前准备 ----> code不是数据库字段，不能入库，username是数据库字段必填，这里没有，写成默认
        self._pre_save(attrs)
        return attrs

    def create(self,validated_data):  # # {mobile:122222,password:123,username:名字}
        # 为什么要重写create？ 因为密码是加密的，如果不写用的models序列化类的，不会给密码加密
        # User.objects.create(**validated_data)  # 密码是明文，必须重写
        user = User.objects.create_user(**validated_data)  # 保存成功，密码就是加密的
        return user


class UserSmsRegisterSerializer(serializers.Serializer):
    mobile = serializers.CharField()
    # password = serializers.CharField()
    code = serializers.CharField(max_length=4,min_length=4,write_only=True)


    def validate(self,attrs):
        # 1.前端传入的手机和验证码先做校验
        mobile = attrs.get('mobile')
        code = attrs.get('code')
        old_code = cache.get('send_sms_mobile%s' % mobile)
        if not (old_code == code or (settings.DEBUG and code == '8888')):
            raise APIException('验证码错误')
        # 2.删除验证码，把手机号码存进数据库，并且随机生成密码重写create方法存入数据库
        attrs.pop('code')
        fake = Faker(locale='zh_CN')

        random_name = fake.name()
        attrs['username'] = random_name  # 默认用户名就是手机号  可以随机生成用户名  随机生成有意义的名字（ Faker）
        password = six_password(6)

        attrs['password'] = password
        # 发送短信通知用户
        # 前端需要把要发送的手机号传入在地址栏中
        # mobile = request.query_params.get('mobile', None)
        # code = get_code()  # 把code存起来，放在缓存中
        # cache.set('send_sms_code_%s' % mobile, code)
        # 从缓存中取
        # cache.get('send_sms_code_%s' % mobile)
        from libs.send_tx_sms import send_sms_by_mobile
        from threading import Thread
        from utils.common_response import APIResponse
        if mobile:
            # 开启一个线程，执行发送短信
            t = Thread(target=send_sms_by_mobile, args=[mobile, password])
            t.start()

        return attrs
    def create(self,validated_data):  # # {mobile:122222,password:123,username:名字}
        # 为什么要重写create？ 因为密码是加密的，如果不写用的models序列化类的，不会给密码加密
        # User.objects.create(**validated_data)  # 密码是明文，必须重写
        user = User.objects.create_user(**validated_data)  # 保存成功，密码就是加密的
        return user




def six_password(count):
    password = ''
    for i in range(count):
        s = random.randint(1,9)
        password += str(s)
    return password

# class UserUpdatePasswordSerialize(serializers.Serializer):
#     #  前端传入的字段，分析可得出，需要用户名，旧密码和新密码
#     username = serializers.CharField()
#     password = serializers.CharField()
#     old_password = serializers.CharField(write_only=True)
#
#     # 记录三次用户密码修改记录，每次改密码，不能跟之前用过的相同
#     def validated(self,attrs):
#         username = attrs.get('username')
#         password = attrs.get('password')
#         old_password = attrs.get('old_password')
#
#         user = User.objects.filter(username=username).first()
#         if user:
#
#
#         else:
#             raise APIException('手机号没有注册')

